﻿include System
include System::Net
include System::Windows
include System::Windows::Browser
include System::Windows::Controls
include System::Windows::Input
include System::Windows::Media
include System::Windows::Shapes
include System::Windows::Media::Animation
include System::Windows::Media::Imaging # for bitmap
include System::Windows::Threading
include System::Net # for WebClient
include System::Windows::Resources # for WebClient
include System::Windows::Markup # for XamlReader
include System::Collections::Generic
include System::Collections::ObjectModel
#include Microsoft::Scripting::Silverlight # for MakeUri

$slider = me.find_name('slider')
$LayoutRoot = me.find_name('LayoutRoot')
$loadingControl = me.find_name('loadingControl')

$images = List[String].new
$imageflow = nil
$imageflowItem = nil
$c = nil

# Useful for debugging
# $window.alert something.to_s # <-- This can be very informative
$window = window

class ImageFlowItem < System::Windows::Controls::Canvas

  attr_accessor :yRotation, :content, :zOffset, :scale, :xAnimation, :isAnimating
  attr_accessor :X, :duration, :easingFunction
  
  attr_accessor :ItemSelected
  
  def initialize(imageFlowItemXaml)
    super()
    self.content = XamlReader.Load(imageFlowItemXaml)
    self.Children.Add(self.content)
    self.yRotation = 45.0
    self.zOffset = 0.0
    #self.scale = 0.6
    self.xAnimation = nil
    self.isAnimating = false
    self.X = 0
    self.duration = Duration.new(TimeSpan.FromMilliseconds(0))
    self.easingFunction = nil
    
    @Animation = self.content.find_name('Animation')
    @Rotator = self.content.find_name('Rotator')
    @image = self.content.find_name('image')
    @rotationKeyFrame = self.content.find_name('rotationKeyFrame')
    @offestZKeyFrame = self.content.find_name('offestZKeyFrame')
    @scaleYKeyFrame = self.content.find_name('scaleYKeyFrame')
    @scaleXKeyFrame = self.content.find_name('scaleXKeyFrame')
    
    if @Animation != nil
      self.xAnimation = DoubleAnimation.new()
      @Animation.children.add(self.xAnimation)
      Storyboard.set_target(self.xAnimation, self.content)
      Storyboard.set_target_property(self.xAnimation, PropertyPath.new(Canvas.left_property))
    end
    
    @Animation.completed{ |s, e| self.isAnimating = false }
    @Rotator.rotation_y = self.yRotation
    @Rotator.local_offset_z = self.zOffset
    
    @image.mouse_left_button_up{ |s,e|
      index = $c.items.index_of(self)
      $c.IndexSelected(index, false)
      $slider.Value = index
    }
    self
  end 
  
  def SetImageSource(imageURI)
    bi = BitmapImage.new(Uri.new(imageURI, UriKind.Absolute))
    @image.Source = bi
  end
  def SetValues(x, zIndex, r, z, s, d, ease, imageSource)
    if imageSource != nil
      self.SetImageSource(imageSource)
    end
    if not self.isAnimating
      if Canvas.get_left(self) != x
        Canvas.set_left(self, self.X)
      end
    end
        
    @rotationKeyFrame.value = r
    @offestZKeyFrame.value = z
    @scaleYKeyFrame.value = s
    @scaleXKeyFrame.value = s
    
    self.xAnimation.To = x
    if self.duration != d
      self.duration = d
      @rotationKeyFrame.key_time = KeyTime.from_time_span(d.time_span)
      @offestZKeyFrame.key_time = KeyTime.from_time_span(d.time_span)
      @scaleYKeyFrame.key_time = KeyTime.from_time_span(d.time_span)
      @scaleXKeyFrame.key_time = KeyTime.from_time_span(d.time_span)
      self.xAnimation.duration = d
    end
    if self.easingFunction != ease
      self.easingFunction = ease
      @rotationKeyFrame.easing_function = ease
      @offestZKeyFrame.easing_function = ease
      @scaleYKeyFrame.easing_function = ease
      @scaleXKeyFrame.easing_function = ease
      self.xAnimation.easing_function = ease
    end
    self.isAnimating = true
    @Animation.begin()
    System::Windows::Controls::Canvas.set_z_index(self, zIndex)
    self.X = x
  end
end

class ImageFlow < System::Windows::Controls::ItemsControl

  attr_accessor :content, :duration, :easingFunction, :items, :selectedIndex  
  attr_accessor :SelectionChanged
  
  def initialize(imageflowXaml, imageflowItemXaml)
    super()
    self.content = XamlReader.Load(imageflowXaml)
    @imageflowItemXaml = imageflowItemXaml
    self.easingFunction = CubicEase.new()
    self.items = List[ImageFlowItem].new
    @objectToItemContainer = Dictionary[Object, ImageFlowItem].new()
    self.duration = Duration.new(TimeSpan.FromMilliseconds(600))
    self.selectedIndex = 0
    
    @k = 140 # SpaceBetweenSelectedItemAndItems
    @l = 40 # SpaceBetweenItems
    @r = 50 # RotationAngle
    @z = 0 # ZDistance
    @s = 0.6 # Scale
    
    self
  end
  
  def GetSelectedIndex
    self.selectedIndex
  end
  def SetSelectedIndex(value)
    IndexSelected(value, false, false)
  end
  def IndexSelected(*args)
    if args.size == 2
      IndexSelected(args[0], args[1], false)
    elsif args.size == 3
      self.selectedIndex = args[0]
      self.LayoutChildren()
    end
  end
  
  def GetContainerForItemOverride()
    ImageFlowItem.new(@imageflowItemXaml)
  end
  
  def PrepareContainerForItemOverride(element, item)
    item2 = element
    if item2 != item
      @objectToItemContainer[item] = item2
    end
    if not self.items.Contains(item2)
      self.items.Add(item2)
      item2.ItemSelected do |s, e|
        item = e.Parent
        if item == nil
          return
        end
        index = self.items.IndexOf(item)
        if index >= 0
          self.IndexSelected(index, nil, false)
        end
      end
      item2.SizeChanged do |s, e|
        item = s
        index = self.items.IndexOf(item)
        LayoutChild(item, index) 
      end
    end
    if self.items.Count == 1
      IndexSelected(0, false, false)
    end
  end
  
  def ClearContainerForItemOverride(element, item)
    item2 = element
    if item2 != item
      @objectToItemContainer.Remove(item)
    end
    self.items.Remove(item2)
  end
  
  def LayoutChildren()
    for i in 0...items.Count do
      LayoutChild(self.items[i], i)
    end
  end
  
  def LayoutChild(item, index)
    width = self.actual_width
    #width = 800.0
    m = width / 2
    b = index - self.selectedIndex
    
    mu = 0
    if b < 0
      mu = -1
    elsif b > 0
      mu = 1
    end
        
    x = (m + (b * @l + (@k * mu))) - (item.content.actual_width / 2)
    if mu == 0
      s = 1.0
    else
      s = @s
    end
    
    zindex = self.items.Count - b.abs
    item.SetValues(x, zindex, @r * mu, @z * mu.abs, s, self.duration, self.easingFunction, self.items_source[index])
  end
  
  def ArrangeOverride(finalSize)
    height = self.actual_height 
    width = self.actual_width
    
    m = width / 2
    
    (0...self.items.Count).each do |i|
      @items[i].content.Height = height
      item = self.items[i]
      b = i - self.selectedIndex
      
      mu = 0
      if b < 0
        mu = -1
      elsif b > 0
        mu = 1
      end
      x = (m + (b * @l + (@k * mu))) - (width / 2)
      
      if mu == 0
        s = 1.0
      else
        s = @s
      end
      
      zindex = @items.Count - b.abs

      item.SetValues(x, zindex, @r * mu, @z * mu.abs, s, self.duration, self.easingFunction, nil)      
    end
    super(finalSize)
  end 
end

# This is called when the LoadImageflowItem method finishes
def LoadImageflow
  client1 = WebClient.new
  client1.DownloadStringCompleted do |s, e|
    $imageflow = e.Result
    Main()
  end  
  #client1.DownloadStringAsync(MakeUri('ImageFlowIC.xaml'))
  client1.DownloadStringAsync(Uri.new('../samples/Imageflow/ImageFlowIC.xaml', UriKind.RelativeOrAbsolute))
end
# This is called by the main method to begin making the imageflow control
def LoadImageflowItem
  client2 = WebClient.new
  client2.DownloadStringCompleted do |s, e|
    $imageflowItem = e.Result
    LoadImageflow()
  end
  #client2.DownloadStringAsync(MakeUri('ImageFlowItem.xaml'))
  client2.DownloadStringAsync(Uri.new('../samples/Imageflow/ImageFlowItem.xaml', UriKind.RelativeOrAbsolute))
  
end

def Main    
  # find all of the images on the page that have the right classname
  imagesOnPage = document.get_elements_by_tag_name('img')
  
  imagesOnPage.each do |element|
    if element.className == 'imageflow'
      $images.Add(element.src)
    end
  end
  
  $c = ImageFlow.new($imageflow, $imageflowItem)
  $c.items_source = $images
  $c.SelectionChanged { |s,e| $slider.Value = $c.selectedIndex }
  
  $LayoutRoot.Children.Add($c)
  
  # disappear the loading throbber
  # set slider maximum value to correspond with number of images
  $loadingControl.Visibility = Visibility.Collapsed
  $slider.Maximum = $images.Count - 1
end

$slider.ValueChanged do |s,e|
  $c.SetSelectedIndex($slider.Value)
  $slider.Value = $slider.Value.round
end

# Start loading up the xaml
LoadImageflowItem()
